package cn.qitom.gateway.filter;

import cn.dev33.satoken.stp.StpUtil;
import cn.qitom.gateway.props.DynamicAllowProperties;
import cn.qitom.gateway.provider.AuthProvider;
import cn.qitom.gateway.provider.ResponseProvider;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * 鉴权认证
 *
 */
@RequiredArgsConstructor
@Component
public class AuthFilter implements GlobalFilter, Ordered {
	private final DynamicAllowProperties allowProperties;
	private final ObjectMapper objectMapper;
	private final AntPathMatcher antPathMatcher = new AntPathMatcher();

	//@Value("${spring.sa-token.token-name}")
	private  String tokenName = "satoken";

	private boolean isAllow(String path) {
		return AuthProvider.getDefaultAllowUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path))
				|| allowProperties.getAllowUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
	}
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		//校验 Token 放行
		ServerHttpRequest request = exchange.getRequest();
		String rawPath = request.getURI().getRawPath();
		String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
				.skip(1L).collect(Collectors.joining("/"));
		String path = exchange.getRequest().getURI().getPath();
		if (isAllow(path) || isAllow(newPath)) {
			return chain.filter(exchange);
		}
		//校验 Token 合法性
		ServerHttpResponse resp = exchange.getResponse();
		String headerToken = exchange.getRequest().getHeaders().getFirst(tokenName);
		Object loginIdByToken = StpUtil.getLoginIdByToken(headerToken);
		if (null==loginIdByToken) {
			return unAuthorized(resp, "缺失鉴权令牌,请求失败");
		}
		return chain.filter(exchange);
	}

	private Mono<Void> unAuthorized(ServerHttpResponse resp, String msg) {
		resp.setStatusCode(HttpStatus.UNAUTHORIZED);
		resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
		String result = "";
		try {
			result = objectMapper.writeValueAsString(ResponseProvider.unAuth(msg));
		} catch (JsonProcessingException e) {
		   e.printStackTrace();
		}
		DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
		return resp.writeWith(Flux.just(buffer));
	}


	@Override
	public int getOrder() {
		return -999;
	}

}
